/*
 * Copyright 2012-2014 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.jqd.framework.core.hessian.biz.action.support;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;

import com.jqd.framework.core.exception.BusinessServiceException;
import com.jqd.framework.core.hessian.model.ServiceRequest;
import com.jqd.framework.core.hessian.model.ServiceResponse;

/**
 * 
 * TODO
 * 
 * @author liaozhicheng.cn@gmail.com
 * @date 2012-6-11
 * @since 1.0
 */
public class MultiMethodAction extends AbstractAction implements InitializingBean {
	
	private static final Log log = LogFactory.getLog(MultiMethodAction.class);
	
	// 通过配置文件配置
	// key ：映射的actionId
	// value ：方法名称
	private Properties actionMappings = new Properties();
	
	private final Map<String, Method> mappingHandlerMethods = new HashMap<String, Method>();
	
	
	@Override
	protected ServiceResponse executeActionInternal(ServiceRequest serviceRequest)
			throws BusinessServiceException {
		
		ServiceResponse serviceResponse = null;
		
		try {
			String actionId = serviceRequest.getRequestedActionID();
			Method hanlerMethod = mappingHandlerMethods.get(actionId);
			
			// 如果没有找到该actionId对应的方法，说明用户没在配置文件中指定该actionId对应的methodName
			if (hanlerMethod == null) {
				throw new BusinessServiceException(
						"No method found for mapping REQUESTED_ACTION_ID : " + actionId);
			}
			
			if (log.isInfoEnabled()) {
				log.info(new StringBuilder().append("==== mapping [").append(actionId)
						.append("] --> ").append(this.getClass().getName()).append("#")
						.append(hanlerMethod.getName()).append("() ====").toString());
			}
			
			serviceResponse = (ServiceResponse) hanlerMethod.invoke(this, serviceRequest);
		}
		catch (Exception ex) {
			throw new BusinessServiceException(ex);
		}
		return serviceResponse;
	}
	
	
	// ------------------------------------------
	// implements InitializingBean interface
	// ------------------------------------------
	
	// 在bean被实例化之后，根据用户配置的actionMappings属性，找到
	// 所有actionId 与 method 的映射，并保存在Map中缓存
	@Override
	public void afterPropertiesSet() throws Exception {
		if (this.actionMappings.isEmpty()) {
			// 如果用户没有配置任何映射，当做异常处理
			throw new BusinessServiceException("No action mapping config found in class [ "
					+ this.getClass() + " ]");
		}
		
		for (Map.Entry<?, ?> entry : this.actionMappings.entrySet()) {
			try {
				String methodName = (String) entry.getValue();
				Method handlerMethod = this.getClass().getMethod(methodName, ServiceRequest.class);
				
				this.mappingHandlerMethods.put((String) entry.getKey(), handlerMethod);
			}
			catch (NoSuchMethodException ex) {
				// 根据用户配置的actionId -> methodName的映射找不到该方法
				throw new BusinessServiceException("No method found with name '" + entry.getValue()
						+ "', REQUESTED_ACTION_ID is '" + entry.getKey() + "' in class [ "
						+ this.getClass() + " ]", ex);
			}
		}
	}
	
	
	// ------------------------------------
	// getter and setter
	// ------------------------------------
	
	/**
	 * @return the actionMappings
	 */
	public Properties getActionMappings() {
		return actionMappings;
	}
	
	
	/**
	 * @param actionMappings
	 *            the actionMappings to set
	 */
	public void setActionMappings(Properties actionMappings) {
		this.actionMappings = actionMappings;
	}
	
}
